package com.martian.service.redis;

import com.martian.common.constant.RedisKeyTemplate;
import com.martian.common.constant.TokenInfo;
import com.martian.common.util.RedisKeyUtil;
import com.martian.common.util.RedisUtil;
import com.martian.pojo.dto.MovieSimilarDto;
import com.martian.pojo.dto.RecMovieDto;
import com.martian.pojo.dto.UserScanHistoryDto;
import com.martian.service.redis.RedisRepository;
import io.swagger.models.auth.In;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.DefaultTypedTuple;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author martian
 * @version V1.0.0
 * @Description
 * @date 2023-03-24 14:17
 */

@Component
public class RedisRepositoryImpl implements RedisRepository {

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 以token字符串为key，userId为valye，存放在TOKEN文件夹下
     * @param tokenInfo
     * T_ACCESS_TOKEN 为 TOKEN:%s
     */
    @Override
    public void saveAccessToken(TokenInfo tokenInfo) {
        String key = RedisKeyUtil.buildKey(RedisKeyTemplate.T_ACCESS_TOKEN, tokenInfo.getAccessToken());
        RedisUtil.set(redisTemplate, key, tokenInfo.getUserId(),60*60, TimeUnit.SECONDS);
    }

    /**
     * 以userId字符串为key，token为valye，存放在USER_ID_TOKEN文件夹下
     * @param tokenInfo
     */
    @Override
    public void saveLoginAccessToken(TokenInfo tokenInfo) {
        String key = RedisKeyUtil.buildKey(RedisKeyTemplate.T_USER_CURRENT_TOKEN, tokenInfo.getUserId());
        RedisUtil.set(redisTemplate, key, tokenInfo.getAccessToken(),60*60,TimeUnit.SECONDS);
    }

    @Override
    public void saveManagerLoginToken(TokenInfo tokenInfo) {
        String key = RedisKeyUtil.buildKey(RedisKeyTemplate.T_MANAGER_CURRENT_TOKEN, tokenInfo.getUserId());
        RedisUtil.set(redisTemplate, key, tokenInfo.getAccessToken(),60*60,TimeUnit.SECONDS);
    }

    @Override
    public void saveManagerLoginId(TokenInfo tokenInfo) {
        String key = RedisKeyUtil.buildKey(RedisKeyTemplate.MANAGER_ACCESS_TOKEN, tokenInfo.getAccessToken());
        RedisUtil.set(redisTemplate, key, tokenInfo.getUserId(),60*60,TimeUnit.SECONDS);
    }

    @Override

    public String selectAccessToken(String accessToken) {
        //    "TOKEN:%s"
        return RedisUtil.<String>get(redisTemplate, RedisKeyUtil.buildKey(RedisKeyTemplate.T_ACCESS_TOKEN, accessToken), String.class);
    }

    @Override
    public String selectLoginAccessToken(Integer userId) {
//        USER_TOKEN:userId
//        T_USER_CURRENT_TOKEN => USER_TOKEN:%s
        return RedisUtil.<String>get(redisTemplate, RedisKeyUtil.buildKey(RedisKeyTemplate.T_USER_CURRENT_TOKEN, userId), String.class);
    }

    @Override
    public String selectManagerLoginToken(Integer managerId) {
        return RedisUtil.<String>get(redisTemplate, RedisKeyUtil.buildKey(RedisKeyTemplate.T_MANAGER_CURRENT_TOKEN, managerId), String.class);
    }

    @Override
    public String selectManagerLoginIdByToken(String accessToken) {
        return RedisUtil.<String>get(redisTemplate, RedisKeyUtil.buildKey(RedisKeyTemplate.MANAGER_ACCESS_TOKEN, accessToken), String.class);
    }

    @Override
    public MovieSimilarDto selectSimilarMovieIdsById(Integer movieId) {
        String key = RedisKeyUtil.buildKey(RedisKeyTemplate.SIMILAR_MOVIE, movieId);
        //redis数据结构Zset,将查到的电影ID根据相似度进行排序
        Set<String> movieIds = redisTemplate.boundZSetOps(key).reverseRange(0,-1);
        if (movieIds.size()==0){
            return null;
        }
        List<Integer> results = new ArrayList<>();
        StringBuffer movieStr = new StringBuffer();
//        movieStr.append(",");
        //获取ids还需要记录相似度顺序，后续根据id多表联查，最后排序时根据下面记录的相似度顺序movieStr排序
        for (String id : movieIds) {
            results.add(Integer.valueOf(id));
            movieStr.append(",");
            movieStr.append(Integer.valueOf(id));
        }
        movieStr.append(",");//,,1151,136556,158027,27619,633,187717,146662,164226,99,158882,
        return new MovieSimilarDto(movieStr.toString(),results);
    }

    /**
     * 删除TOKEN文件夹下的，以TOKEN字符串为key，UserId为Value的
     * @param accessToken
     */
    @Override
    public void deleteAccessToken(String accessToken) {
        RedisUtil.del(redisTemplate, RedisKeyUtil.buildKey(RedisKeyTemplate.T_ACCESS_TOKEN, accessToken));
    }

    @Override
    public void deleteLoginAccessToken(Integer userId) {
        RedisUtil.del(redisTemplate, RedisKeyUtil.buildKey(RedisKeyTemplate.T_USER_CURRENT_TOKEN, userId));
    }

    @Override
    public void deleteManagerLoginToken(String Token) {
        RedisUtil.del(redisTemplate, RedisKeyUtil.buildKey(RedisKeyTemplate.T_MANAGER_CURRENT_TOKEN, Token));
    }

    @Override
    public void deleteManagerLoginId(Integer managerId) {
        RedisUtil.del(redisTemplate, RedisKeyUtil.buildKey(RedisKeyTemplate.T_MANAGER_CURRENT_TOKEN, managerId));
    }

    @Override
    public String selectUserEmb(Integer userId){
        return RedisUtil.<String> get(redisTemplate, RedisKeyUtil.buildKey(RedisKeyTemplate.USER_EMB, userId), String.class);
    }

    @Override
    public String selectMovieItemEmb(Integer movieId){
        return RedisUtil.<String>get(redisTemplate, RedisKeyUtil.buildKey(RedisKeyTemplate.MOVIE_ITEM_EMB, movieId), String.class);
    }
    @Override
    public String selectMovieDeepWalkEmb(Integer movieId){
        return RedisUtil.<String>get(redisTemplate, RedisKeyUtil.buildKey(RedisKeyTemplate.MOVIE_DEEPWALK_EMB, movieId), String.class);
    }

    @Override
    public void saveUserHistory(Integer userId,Integer movieId) {
        String key = RedisKeyUtil.buildKey(RedisKeyTemplate.USER_HISTORY, userId);
        RedisUtil.setZSets(redisTemplate, key, String.valueOf(movieId));
    }

    @Override
    public UserScanHistoryDto selectUserScanHistory(Integer userId) {
        String key = RedisKeyUtil.buildKey(RedisKeyTemplate.USER_HISTORY, userId);
        Set<String> movieIds = redisTemplate.boundZSetOps(key).range(0,-1);
        List<Integer> results = new ArrayList<>();
        StringBuffer movieIdStr = new StringBuffer();
        movieIdStr.append(",");
        for (String movieId : movieIds) {
            movieIdStr.append(movieId+',');
            results.add(Integer.valueOf(movieId));
        }
        movieIdStr.append(",");
        UserScanHistoryDto userScanHistoryDto = new UserScanHistoryDto(movieIdStr.toString(),results);
        return userScanHistoryDto;
    }

    @Override
    public Long getNumOfUserHistory(Integer userId) {
        String key = RedisKeyUtil.buildKey(RedisKeyTemplate.USER_HISTORY, userId);
        return redisTemplate.opsForZSet().size(key);
    }

    @Override
    public void savaMovieSimilars(List<Map.Entry<RecMovieDto,Double>> similarMovies,Integer movieId) {
        String key = RedisKeyUtil.buildKey(RedisKeyTemplate.SIMILAR_MOVIE, movieId);
        Set<ZSetOperations.TypedTuple<String>> results = new HashSet<>();
        for (Map.Entry<RecMovieDto,Double> entry : similarMovies) {
            DefaultTypedTuple<String> similar = new DefaultTypedTuple<>(entry.getKey().getMovieId().toString(), entry.getValue());
            results.add(similar);
        }
        redisTemplate.boundZSetOps(key).add(results);
    }
}
